package com.ibm.spatiotemp.processor;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import com.ibm.spatiotemp.datamodel.datatype.TemporalLineString;
import com.ibm.spatiotemp.server.config.LocalConfig;

import edu.umn.cs.spatialHadoop.core.Shape;

public class SearcherFactory {

	public static Logger logger = Logger.getLogger(SearcherFactory.class);
	
	/**
	 * generate time range as a part of hdfs's index storage path, schema is "startmark_endmark"
	 * @param startts: unit msecond
	 * @param endts : unit msecond
	 * @param scale: unit second
	 * @return
	 */
	private static String[] computeTimeRangeMarkers(long startts, long endts, long scale)
	{
		scale *= (long)1000;
		int startscale = (int)(startts/scale);
		int endtsscale = endts % scale != 0 ? (int)((endts/scale)+1) : (int)(endts/scale);
		if(endtsscale <= startscale)
			return null;
		
		String[] res = new String[ (endtsscale - startscale)];
		for (int i = 0; i < endtsscale-startscale; i++) {
			res[i] = (i+startscale)+"_"+(i+startscale+1);
		}
		return res;
	}
	
	/**
	 * 
	 * @param dsrcname
	 * @param startts
	 * @param endts
	 * @param scale
	 * @return
	 */
	public static SpatialSearcher[] getSpatialSearcher_1stLayer(String dsrcname, long startts, long endts, long scale){
		
		String[] trmarks = computeTimeRangeMarkers(startts, endts, scale);
		if(trmarks == null)
			return null;
		else
		{
			SpatialSearcher[] resobjs = new SpatialSearcher[trmarks.length];
			for (int i = 0; i < trmarks.length; i++) {
				String indexpath = String.format(LocalConfig.IndexPathFormat1stLayer, dsrcname, trmarks[i]);
				resobjs[i] = getSearcherInstance(indexpath);
			}
			return resobjs;
		}
	}
	
	/**
	 * Map: key: modid, value: related searchers 
	 * @param dsrcname
	 * @param modids
	 * @param startts
	 * @param endts
	 * @param scale
	 * @return
	 */
	public static Map<String, SpatialSearcher[]> getSpatialSearcher_2ndLayer(String dsrcname, Collection<String> modids, long startts, long endts, long scale){
		if(modids == null || modids.isEmpty())
			return null;
		Map<String, SpatialSearcher[]> resmap = new HashMap<String, SpatialSearcher[]>();
		for (String modid: modids) {
			resmap.put(modid, getSpatialSearcher_2ndLayer(dsrcname, modid,startts,endts,scale));
		}
		return resmap;
	}
	
	private static SpatialSearcher[] getSpatialSearcher_2ndLayer(String dsrcname, String modid, long startts, long endts, long scale)
	{
		String[] trmarks = computeTimeRangeMarkers(startts, endts, scale);
		if(trmarks == null)
			return null;
		else
		{
			SpatialSearcher[] resobjs = new SpatialSearcher[trmarks.length];
			for (int i = 0; i < trmarks.length; i++) {
				String indexpath = String.format(LocalConfig.IndexPathFormat2ndLayer, dsrcname, modid, trmarks[i]);
				resobjs[i] = getSearcherInstance(indexpath);
			}
			return resobjs;
		}
	}
	
	public static SpatialSearcher getSearcherInstance(String idxpath) 
	{
		if(LocalConfig.RunningLevel == LocalConfig.RunningLevel_Debug)
			return getSearcherInstance(LocalConfig.RtreePath4Debug,  new TemporalLineString());
		else
			return getSearcherInstance(idxpath,  new TemporalLineString());
	}

	private static SpatialSearcher getSearcherInstance(String idxpath, Shape classobj) 
	{
		SpatialSearcher searcher = null;
		try {
			searcher = new RtreeSearcher2<>(idxpath, classobj, LocalConfig.NeedLoadToCache);
		} catch (Exception e) {
			logger.error("cannot build spatialsearcher " + e);
		}
		return searcher;
	}
	

}
